home *** CD-ROM | disk | FTP | other *** search
/ DOpus Plus / DOpus Plus.iso / Tutorial / C Guide / Average_Module1 / DOExchange.c < prev    next >
C/C++ Source or Header  |  1998-10-09  |  36KB  |  908 lines

  1. /*******************************************************************
  2.  
  3.    DOExchange.c
  4.    
  5.    It's a try to do the Exchange work within a dopus popup menu.
  6.    
  7.    Since nothing of the commodities.library is really documented,
  8.    this source may be wrong. If you know more, you may change/add
  9.    what is to do...
  10.    
  11.    SO BE WARNED... - THIS IS A HACK !!
  12.    (even if it seems to be OK)
  13.    
  14.    Initial idea by Jens Weyer. 
  15.    
  16. *********************************************************************/
  17.  
  18. #include "includes/DOExchange.h"
  19.  
  20. /********************************************************************/
  21. // some prototypes
  22.  
  23. ULONG __asm __saveds New_Proc_Startup( register __a0 IPCData *ipc,
  24.                                        register __a1 DOE_Data *dd );
  25.  
  26. void __saveds New_Proc( void );
  27. void CleanUp( DOE_Data *dd, IPCData *ipc );
  28.  
  29. BOOL OpenWin( DOE_Data *dd );
  30. void BorderDraw( DOE_Data *dd, BOOL invers );
  31.  
  32. BOOL InitPopupMenu( DOE_Data *dd );
  33. APTR CreateSubMenu( DOE_Data *dd, ULONG from, ULONG to );
  34. void ClearPopupMenu( DOE_Data *dd );
  35. BOOL DoMenu( DOE_Data *dd );
  36.  
  37. BOOL HandleWin( DOE_Data *dd );
  38. BOOL HandleCX( DOE_Data *dd );
  39. BOOL HandleNotify( DOE_Data *dd );
  40. BOOL HandleIPC( DOE_Data *dd );
  41.  
  42. BOOL SendCxMsg( CX_OBJ *cxobj, ULONG type, struct MsgPort *reply_to );
  43.  
  44. BOOL WriteConfig( DOE_Data *dd );
  45. BOOL ReadConfig( DOE_Data *dd );
  46.  
  47. /********************************************************************/
  48. // it is surely useful to detach here
  49.  
  50. void DOExchange( STRPTR args, struct Screen *screen, IPCData *ipc )
  51. {
  52.      DOE_Data *dd;
  53.      FuncArgs *fargs;
  54.       
  55.      if( !exchange )
  56.        {
  57.           if( (dd = AllocMemH(mempool, sizeof(DOE_Data))) )
  58.             {
  59.                dd->screen  = screen;
  60.                dd->a4      = getreg( REG_A4 );
  61.                dd->module  = (struct Library *) getreg( REG_A6 );
  62.                dd->library = DOpusBase;
  63.           
  64.                IPC_Launch( 0, 
  65.                            &exchange,         // pointer to pointer to the IPC of the new process, for storing...
  66.                            "DOpus Exchange",  // name of the new process
  67.                            (ULONG) New_Proc,  // entrypoint of the new process
  68.                            4096,              // stack to use
  69.                            (ULONG) dd,        // data to pass to the new process
  70.                            DOSBase );         // pointer to dos.library
  71.                          
  72.                if( !exchange )                // if detaching failed...
  73.                  {
  74.                     FreeMemH( dd );
  75.                     return;
  76.                  }
  77.             }
  78.        }
  79.        
  80.      if( args )
  81.        {  
  82.           if( (fargs = ParseArgs(FUNC0_TEMPLATE, args)) )
  83.             {
  84.                ULONG cmd = 0, counter;
  85.                PassData *pd;
  86.                
  87.                for( counter = 0; counter < TEMPLATE_COUNT; counter++ )
  88.                     if( fargs->FA_Arguments[counter] )
  89.                          cmd |= 1 << counter;
  90.                
  91.                if( (pd = AllocVec(sizeof(PassData), MEMF_CLEAR)) )
  92.                  {
  93.                     pd->FrontPen = ARG_TC   ? *(ULONG *) ARG_TC   : NULL;
  94.                     pd->BackPen  = ARG_BGC  ? *(ULONG *) ARG_BGC  : NULL;
  95.                     pd->name     = ARG_NAME ? (STRPTR)   ARG_NAME : NULL;
  96.                     
  97.                     IPC_Command( exchange, 
  98.                                  cmd,
  99.                                  NULL,
  100.                                  NULL,
  101.                                  pd,              // FreeVec the data automatically
  102.                                  REPLY_NO_PORT );
  103.                   }
  104.                                               
  105.                DisposeArgs( fargs );
  106.              }
  107.        }      
  108. }
  109.  
  110. /********************************************************************/
  111.  
  112. ULONG __asm __saveds New_Proc_Startup( register __a0 IPCData *ipc,
  113.                                        register __a1 DOE_Data *dd )
  114. {     
  115.         struct Library *DOpusBase; 
  116.  
  117.         putreg( REG_A4, dd->a4 );
  118.         dd->ipc = ipc;
  119.         DOpusBase = dd->library;
  120.  
  121.         // now follows our initialization
  122.         
  123.         dd->module->lib_OpenCnt++;
  124.         
  125.         // the default button text
  126.         dd->itext.IText = DOpusGetString( locale, MSG_TEXT );
  127.         dd->itext.FrontPen = 1;
  128.         
  129.         ReadConfig( dd );
  130.         
  131.         if( strlen(dd->name) )
  132.              dd->itext.IText = dd->name;
  133.                 
  134.         // install our notify
  135.         if( !(dd->notify_port   = CreateMsgPort()) ||
  136.             !(dd->notify_handle = AddNotifyRequest(DN_OPUS_HIDE | DN_OPUS_SHOW | DN_OPUS_QUIT |
  137.                                                    DN_CLOSE_WORKBENCH | DN_OPEN_WORKBENCH | DN_RESET_WORKBENCH,
  138.                                                    NULL, dd->notify_port)) )
  139.              return FALSE;
  140.                     
  141.         // fill our newbroker structure
  142.         dd->nb.nb_Version = NB_VERSION;
  143.         dd->nb.nb_Name    = DOpusGetString( locale, FUNC0_DESCRIPTION );
  144.         dd->nb.nb_Title   = dd->nb.nb_Name;
  145.         dd->nb.nb_Descr   = DOpusGetString( locale, MSG_CX_DESCR );
  146.         dd->nb.nb_Unique  = NBU_UNIQUE|NBU_NOTIFY;
  147.         dd->nb.nb_Flags   = COF_SHOW_HIDE;
  148.         
  149.         // create the broker              
  150.         if( !(dd->nb.nb_Port = CreateMsgPort()) ||
  151.             !(dd->our_cxobj  = CxBroker(&dd->nb, (LONG *) &dd->signals)) ||
  152.             dd->signals      ||
  153.             !(dd->sender     = CreateMsgPort()) )
  154.              return FALSE; 
  155.                     
  156.         return TRUE; // all was successfully
  157.  
  158. void __saveds New_Proc( void )
  159. {
  160.      DOE_Data *dd;
  161.      IPCData *ipc;
  162.      struct Library *DOpusBase;
  163.            
  164.      if( !(DOpusBase = (struct Library *) FindName(&((struct ExecBase *)*((ULONG *)4))->LibList, "dopus5.library")) )
  165.           return;
  166.      
  167.      ipc = IPC_ProcStartup( (ULONG *) &dd, New_Proc_Startup );
  168.      putreg( REG_A4, dd->a4 );
  169.      
  170.      if( !ipc )
  171.        {
  172.           if( dd )
  173.                CleanUp( dd, dd->ipc );
  174.                       
  175.           return;
  176.        }
  177.           
  178.      // make our broker aktive
  179.      ActivateCxObj( dd->our_cxobj, TRUE );
  180.                  
  181.      // open the window (looks like a dopus button)            
  182.      if( OpenWin(dd) )
  183.        {                 
  184.           while( TRUE )
  185.             {
  186.                dd->signals = Wait( 1 << dd->sender->mp_SigBit            |                 // reply port of our sended messages
  187.                                    1 << dd->nb.nb_Port->mp_SigBit        |
  188.                                    1 << dd->notify_port->mp_SigBit       |                                 
  189.                                    1 << dd->ipc->command_port->mp_SigBit |                 // ipc messages
  190.                                    (dd->win ? 1 << dd->win->UserPort->mp_SigBit : NULL) ); // IDCMP messages
  191.                
  192.                if( dd->signals & 1 << dd->sender->mp_SigBit ) // our message does return
  193.                  {
  194.                     while( (dd->fmsg = (FakeMsg *) GetMsg(dd->sender)) )
  195.                          FreeMemH( dd->fmsg );                // we have only to free the memory
  196.                  }
  197.                  
  198.                dd->stop = FALSE;
  199.                          
  200.                if( dd->signals & 1 << dd->nb.nb_Port->mp_SigBit )
  201.                  {
  202.                     if( HandleCX(dd) )
  203.                          break;
  204.                  } 
  205.                  
  206.                if( dd->signals & 1 << dd->notify_port->mp_SigBit )
  207.                  {
  208.                     if( HandleNotify(dd) )
  209.                          break;                    
  210.                  } 
  211.                  
  212.                if( dd->signals & 1 << dd->ipc->command_port->mp_SigBit )
  213.                  {
  214.                     if( HandleIPC(dd) )
  215.                          break;
  216.                  } 
  217.                
  218.                if( dd->win && (dd->signals & 1 << dd->win->UserPort->mp_SigBit) )
  219.                  {
  220.                     if( HandleWin(dd) )
  221.                          break;
  222.                  }            
  223.             }       
  224.        }
  225.    
  226.      CleanUp( dd, exchange );
  227.      exchange = NULL;       
  228. }
  229.  
  230. void CleanUp( DOE_Data *dd, IPCData *ipc )
  231. {
  232.      if( dd->win )
  233.           CloseWindow( dd->win );
  234.                
  235.      if( dd->notify_port )
  236.        {
  237.           if( dd->notify_handle )
  238.                RemoveNotifyRequest( dd->notify_handle );
  239.                     
  240.           while( !IsMsgPortEmpty( dd->notify_port) )
  241.                ReplyFreeMsg( GetMsg(dd->notify_port) );
  242.                          
  243.           DeleteMsgPort( dd->notify_port );
  244.        }
  245.        
  246.      DeleteCxObjAll( dd->our_cxobj );
  247.      
  248.      if( dd->nb.nb_Port )
  249.        {
  250.           while( !IsMsgPortEmpty(dd->nb.nb_Port) )
  251.                ReplyMsg( GetMsg(dd->nb.nb_Port) );
  252.           
  253.           DeleteMsgPort( dd->nb.nb_Port );
  254.        }
  255.        
  256.      if( dd->sender )
  257.        {
  258.           while( !IsMsgPortEmpty(dd->sender) )
  259.                FreeMemH( GetMsg(dd->sender) );
  260.           
  261.           DeleteMsgPort( dd->sender );
  262.        }
  263.    
  264.      dd->module->lib_OpenCnt--;
  265.      
  266.      FreeMemH( dd );
  267.      
  268.      IPC_Free( ipc );
  269.      
  270. }
  271.  
  272. /********************************************************************/
  273.  
  274. BOOL OpenWin( DOE_Data *dd )
  275. {    
  276.      // lock the screen   
  277.      if( (dd->screen = LockPubScreen(NULL)) )
  278.        {
  279.           if( (dd->win = OpenWindowTags(  NULL,
  280.                                           WA_Left,   dd->ibox.Left,
  281.                                           WA_Top,    dd->ibox.Top,
  282.                                           WA_Height, dd->screen->Font->ta_YSize + 4,
  283.                                           WA_Width,  IntuiTextLength( &dd->itext ) + 5,
  284.                                     
  285.                                           WA_Gadgets, &draggadget,
  286.                                     
  287.                                           WA_Flags,   WFLG_BORDERLESS | WFLG_NEWLOOKMENUS |
  288.                                                       WFLG_SMART_REFRESH | WFLG_RMBTRAP,
  289.                                                 
  290.                                           WA_IDCMP,   IDCMP_MOUSEBUTTONS,
  291.                                                 
  292.                                           WA_AutoAdjust, TRUE,                                  
  293.                                           WA_PubScreen, dd->screen,
  294.                                           WA_ScreenTitle, (STRPTR) ~0,
  295.                                           TAG_DONE)) )
  296.             {  
  297.                // register our window, so it does get messages
  298.                // even it is inactive
  299.                SetWindowID( dd->win, &dd->id, 0x1400, 0 );
  300.               
  301.                BorderDraw( dd, FALSE );          
  302.             }
  303.      
  304.           UnlockPubScreen( NULL, dd->screen );
  305.        }
  306.            
  307.      return (BOOL) dd->win;     
  308. }
  309.  
  310. void BorderDraw( DOE_Data *dd, BOOL invers )
  311. {     
  312.    // flood the port with supplied colour
  313.    SetRast( dd->win->RPort, dd->itext.BackPen );
  314.    
  315.    // draw a border         
  316.    SetAPen( dd->win->RPort, invers ? 2 : 1 );
  317.    Move( dd->win->RPort, 1, dd->win->Height - 1 );
  318.    Draw( dd->win->RPort, dd->win->Width-1, dd->win->Height - 1 );
  319.    Draw( dd->win->RPort, dd->win->Width-1, 1 );
  320.      
  321.    SetAPen( dd->win->RPort, invers ? 1 : 2 );
  322.    Move( dd->win->RPort, 0, dd->win->Height - 1 );
  323.    Draw( dd->win->RPort, 0, 0 );
  324.    Draw( dd->win->RPort, dd->win->Width-1, 0 );  
  325.    
  326.    // set values for the Rastport
  327.    SetRPAttrs( dd->win->RPort, 
  328.                RPTAG_APen, dd->itext.FrontPen,
  329.                RPTAG_BPen, dd->itext.BackPen,
  330.                TAG_DONE );
  331.                  
  332.    // print the button text
  333.    Move( dd->win->RPort, 3, dd->win->RPort->Font->tf_Baseline + 2 );
  334.    Text( dd->win->RPort, dd->itext.IText, strlen(dd->itext.IText) );    
  335. }
  336.  
  337. /********************************************************************/
  338. // popup menu work
  339.  
  340. // do not be worry, most of this things is only needed to allow:
  341. // - unlimited count of entries with their needed submenu
  342. // - easier to do the cleanup
  343.  
  344. BOOL InitPopupMenu( DOE_Data *dd )
  345. {
  346.      dd->entry_count = 0;
  347.      
  348.      // init the lists we need     
  349.      NewList( (struct List *) &dd->popmenu.item_list );
  350.      NewList( (struct List *) &dd->submenus );
  351.      
  352.      // open the popupmenu above our window
  353.      dd->popmenu.flags  = POPUPMF_ABOVE;
  354.      
  355.      // locale pointer, so we must not supply real strings - only ID's
  356.      dd->popmenu.locale = locale;
  357.      
  358.      // since nothing is documented here, I have done what I think:
  359.      // all brokers must be anywhere in a list and if we have one
  360.      // node (our broker), we can access the whole list...
  361.      dd->ptr_node = (struct Node *) dd->our_cxobj;
  362.      
  363.      // the objects does work with interrupts, it may a good idea
  364.      // to protect the access to the list with Disable()
  365.      Disable();
  366.      
  367.      // go to the head of the list
  368.      do
  369.        {
  370.           dd->ptr_node = dd->ptr_node->ln_Pred;
  371.        }
  372.      while( dd->ptr_node->ln_Pred->ln_Pred );    
  373.    
  374.      // now we can create our needed lists - we have here 2 + X (!)
  375.      // first list         - MinList with the names of the objects (needed by DoPopUpMenu)
  376.      // second list        - MinList, each node contain again a MinList (third list)
  377.      //                      this list is only for easy handling for us
  378.      // third (and X) list - MinList for submenu, it does also contain a pointer
  379.      //                      to the cx_object
  380.       
  381.      do
  382.        {
  383.           // this counter is used to give each (main) menu item an ID.
  384.           // since these items have all submenus, you may also give
  385.           // all the same ID (dopus5.library does only pass them through) 
  386.           dd->entry_count++;
  387.                               
  388.           // now it's time to create the menu entry...
  389.           if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) )
  390.             {                    
  391.                dd->popitem->item_name = dd->ptr_node->ln_Name;
  392.                dd->popitem->id        = dd->entry_count;
  393.                
  394.                // each item has a submenu
  395.                if( (dd->popitem->data  = CreateSubMenu(dd, MSG_ACTIVATE, MSG_REMOVE)) )
  396.                     dd->popitem->flags = POPUPF_SUB;
  397.                               
  398.                // the next block is a kind of sorted adding of our nodes
  399.                // since this are MinList's, it is not possible to use DOpus
  400.                // list functions here...
  401.                
  402.                // at first we need a pointer to the first node
  403.                dd->compare = (PopUpItem *) dd->popmenu.item_list.mlh_Head;
  404.                
  405.                if( IsListEmpty((struct List *) &dd->popmenu.item_list) ||  
  406.                    Stricmp(dd->popitem->item_name, dd->compare->item_name) < 0 ) // or our new name is lower
  407.                  {
  408.                     AddHead( (struct List *) &dd->popmenu.item_list,
  409.                              (struct Node *) dd->popitem );
  410.                  }
  411.                else
  412.                  {
  413.                     // walk through the list until a name is higher than our new name or
  414.                     // the list is no more entries                 
  415.                     while( dd->compare->node.mln_Succ->mln_Succ &&
  416.                            Stricmp(dd->popitem->item_name, ((PopUpItem *) dd->compare->node.mln_Succ)->item_name) > 0 )
  417.                             dd->compare = (PopUpItem *) dd->compare->node.mln_Succ;
  418.                   
  419.                     // insert the new node before (!) the higher name is coming
  420.                     // or even append it, if no higher entry does exist
  421.                     Insert( (struct List *) &dd->popmenu.item_list,
  422.                             (struct Node *) dd->popitem,
  423.                             (struct Node *) dd->compare );                
  424.                  }                  
  425.             } 
  426.        }
  427.      while( (dd->ptr_node = dd->ptr_node->ln_Succ)->ln_Succ ); 
  428.    
  429.      // we have not all done now, but we must not access longer the object list,
  430.      // so we can allow again all stuff       
  431.      Enable();
  432.      
  433.      // adding a barlabel
  434.      if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) )
  435.        {
  436.           dd->popitem->item_name = POPUP_BARLABEL;
  437.           dd->popitem->id = 0;
  438.                                  
  439.           AddTail( (struct List *) &dd->popmenu.item_list,
  440.                    (struct Node *) dd->popitem );              
  441.        } 
  442.      
  443.      // adding a item to snap the current settings  
  444.      if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) )
  445.        {
  446.           dd->popitem->item_name = (STRPTR) MSG_SAVE_POS;
  447.           dd->popitem->id        = POPID_SAVE;
  448.           dd->popitem->flags     = POPUPF_LOCALE;
  449.                         
  450.           AddTail( (struct List *) &dd->popmenu.item_list,
  451.                    (struct Node *) dd->popitem );              
  452.        }
  453.      
  454.      // and an item to allow to quit directly
  455.      if( (dd->popitem = AllocMemH(mempool, sizeof(PopUpItem))) )
  456.        {
  457.           dd->popitem->item_name = (STRPTR) MSG_QUIT;
  458.           dd->popitem->id        = POPID_QUIT;
  459.           dd->popitem->flags     = POPUPF_LOCALE;
  460.                         
  461.           AddTail( (struct List *) &dd->popmenu.item_list,
  462.                    (struct Node *) dd->popitem );              
  463.        } 
  464.      
  465.      return TRUE;
  466. }
  467.  
  468. // this routine is already prepared to be copied if you need it :)
  469. // you must change only small things then...
  470.  
  471. APTR CreateSubMenu( DOE_Data *dd, ULONG from, ULONG to )
  472. {
  473.      PopUpItem *popitem;
  474.      
  475.      if( (dd->submenu_node = AllocMemH(mempool, sizeof(SubMenu_Node))) )
  476.        {
  477.           // init the list
  478.           NewList( (struct List *) &dd->submenu_node->submenu );
  479.                
  480.           // getting the items to show
  481.           for( dd->a4 = from; dd->a4 <= to; dd->a4++ )
  482.             {
  483.                // allocate a node 
  484.                if( (popitem = AllocMemH(mempool, sizeof(PopUpItem))) )
  485.                  {
  486.                     // fill the node
  487.                     popitem->item_name = (STRPTR) dd->a4; 
  488.                     popitem->flags     = POPUPF_LOCALE;
  489.                     popitem->id        = dd->a4;
  490.                     popitem->data      = dd->ptr_node; // pointer to the CX_object
  491.                     
  492.                     switch( dd->a4 )
  493.                       {
  494.                          case MSG_ACTIVATE :
  495.                                              popitem->flags |= POPUPF_CHECKIT;
  496.                                              
  497.                                              // now it is again result of hard work and
  498.                                              // may be wrong... :)
  499.                                              // check the current activation state
  500.                                              //if( ((STRPTR) dd->ptr_node)[0x0E] & 1 << 1 )
  501.                                              if( ((CX_OBJ *) dd->ptr_node)->flags & 1 << 1 )
  502.                                                   popitem->flags |= POPUPF_CHECKED;
  503.                                              
  504.                                              break;
  505.                                              
  506.                          case MSG_APPEAR   :
  507.                          case MSG_DISAPPEAR:
  508.                                              // checking if this object has a GUI
  509.                                              //if( !(((STRPTR) dd->ptr_node)[0x0E] & 1 << 2) )
  510.                                              if( !(((CX_OBJ *) dd->ptr_node)->flags & 1 << 2) )
  511.                                                   popitem->flags |= POPUPF_DISABLED;
  512.                       }
  513.                          
  514.                     // add the popitem node to the submenu list
  515.                     AddTail( (struct List *) &dd->submenu_node->submenu,
  516.                              (struct Node *) popitem );
  517.                  }
  518.             }
  519.           // add the submenu list to the second list, so we can free it later all easily  
  520.           AddTail( (struct List *) &dd->submenus,
  521.                    (struct Node *) dd->submenu_node );
  522.           
  523.           return &dd->submenu_node->submenu;
  524.        }
  525.        
  526.      return NULL;     
  527. }
  528.  
  529. // this routines should be clear for everyone...
  530. void ClearPopupMenu( DOE_Data *dd )
  531. {
  532.      while( !IsListEmpty((struct List *) &dd->popmenu.item_list) )
  533.           FreeMemH( RemHead((struct List *) &dd->popmenu.item_list) );
  534.      
  535.      while( !IsListEmpty((struct List *) &dd->submenus) )
  536.        {
  537.           dd->submenu_node = (SubMenu_Node *) RemHead((struct List *) &dd->submenus);
  538.           
  539.           while( !IsListEmpty((struct List *) &dd->submenu_node->submenu) )
  540.                FreeMemH( RemHead((struct List *) &dd->submenu_node->submenu) );
  541.             
  542.           FreeMemH( dd->submenu_node );
  543.        }       
  544. }
  545.  
  546. BOOL DoMenu( DOE_Data *dd )
  547. {
  548.      // preparing the popupmenu
  549.      if( InitPopupMenu(dd) )
  550.        {
  551.           // start the popupmenu
  552.           if( DoPopUpMenu(dd->win, &dd->popmenu, &dd->popitem, MENUDOWN) != -1 )
  553.             {
  554.                // if the previous call does return, dd->popitem contains the user selection
  555.                switch( dd->popitem->id )
  556.                  {
  557.                     case POPID_SAVE : 
  558.                                                 WriteConfig( dd );
  559.                                                 break;
  560.                                           
  561.                     case POPID_QUIT : 
  562.                                                 dd->stop = TRUE;
  563.                                                 break;
  564.                   
  565.                     case MSG_ACTIVATE:     
  566.                     case MSG_APPEAR:     
  567.                     case MSG_DISAPPEAR:
  568.                     case MSG_REMOVE:    // create a fake CxMsg (not documented...)
  569.                                         // and send it to the choosed CxObj
  570.                                                 
  571.                                         SendCxMsg( (CX_OBJ *) dd->popitem->data, // send it to...
  572.                                                    (dd->popitem->id == MSG_ACTIVATE ? (dd->popitem->flags & POPUPF_CHECKED ? CXCMD_ENABLE : CXCMD_DISABLE) : (dd->popitem->id - MSG_ACTIVATE)*2 + 17 ),
  573.                                                    dd->sender ); // use this port to reply to
  574.                                                
  575.                                         break;
  576.                     }
  577.                }   
  578.              // free the menu
  579.              ClearPopupMenu( dd );                 
  580.        }
  581.        
  582.      return dd->stop;      
  583. }
  584.  
  585. /********************************************************************/
  586. // handling routines
  587.  
  588. BOOL HandleWin( DOE_Data *dd )
  589. {        
  590.    while( !dd->stop && (dd->messages = GetMsg(dd->win->UserPort)) )
  591.      {
  592.         // since we are not interested in other messages, we use a simple "if"
  593.         if( ((struct IntuiMessage *) dd->messages)->Class == IDCMP_MOUSEBUTTONS &&
  594.             ((struct IntuiMessage *) dd->messages)->Code == MENUDOWN )
  595.             //&&
  596.             //((ULONG) WhichLayer(&dd->screen->LayerInfo, dd->screen->MouseX, dd->screen->MouseY)) == ((ULONG) dd->win->WLayer) )
  597.           { 
  598.              // since we have no real gadget, the window must be activated
  599.              // else the popup menu may be in some cases not selectable
  600.              ActivateWindow( dd->win );
  601.                                
  602.              // make our window "selected"
  603.              BorderDraw( dd, TRUE );
  604.              
  605.              dd->stop = DoMenu( dd );
  606.              
  607.              // "unselect"           
  608.              BorderDraw( dd, FALSE );
  609.              
  610.              // deactivate our window again (will activate the previous
  611.                  // activated window, if available)
  612.                  
  613.              if( dd->win->NextWindow )
  614.                       ActivateWindow( dd->win->NextWindow );
  615.                  else
  616.                       dd->win->Flags ^= WFLG_WINDOWACTIVE;           
  617.           } 
  618.         ReplyMsg( dd->messages );        
  619.      }     
  620.    
  621.    return dd->stop;
  622. }
  623.  
  624. BOOL HandleCX( DOE_Data *dd )
  625. {  
  626.    while( !dd->stop && (dd->messages = GetMsg(dd->nb.nb_Port)) )
  627.      {
  628.         // on this place we can use some variables for other work...
  629.         dd->a4      = CxMsgType( (CxMsg *) dd->messages );
  630.         dd->signals = CxMsgID((CxMsg *) dd->messages);
  631.         
  632.         // should be so fast as possible...
  633.         ReplyMsg( dd->messages );
  634.                        
  635.         if(  dd->a4 == CXM_COMMAND )
  636.           {                 
  637.              switch( dd->signals )
  638.                {
  639.                   case CXCMD_DISABLE:    // since we are do not handle any
  640.                                          // other things than our window, it
  641.                                          // is a little bit useless to disable/
  642.                                          // enable, but anyway we do it... :)
  643.                                          ActivateCxObj( dd->our_cxobj, FALSE );
  644.                                          break;
  645.                   
  646.                   case CXCMD_ENABLE:    
  647.                                          ActivateCxObj( dd->our_cxobj, TRUE );
  648.                                          break;
  649.                   
  650.                   case CXCMD_APPEAR:     
  651.                                          if( !dd->win )
  652.                                            {
  653.                                               OpenWin( dd );                                                                                           
  654.                                            }
  655.                                          else
  656.                                               WindowToFront( dd->win );
  657.                                          break;
  658.                   
  659.                   case CXCMD_DISAPPEAR:  
  660.                                          if( dd->win )
  661.                                            {
  662.                                               // save our current position temporally
  663.                                               dd->ibox.Left = dd->win->LeftEdge;
  664.                                               dd->ibox.Top  = dd->win->TopEdge;
  665.                                               
  666.                                               CloseWindow( dd->win );
  667.                                               dd->win = NULL;                                             
  668.                                            }
  669.                                          break;
  670.                   
  671.                   case CXCMD_KILL:      
  672.                                          dd->stop = TRUE;
  673.                                          break;
  674.                                          
  675.                                          
  676.                   /* it seems this value needs a special flag in
  677.                      the newbroker structure and so no messages of
  678.                      this ID does arrive here...
  679.                                          
  680.                   case CXCMD_LIST_CHG:
  681.                                          
  682.                                          break;                                       
  683.                   */                
  684.                }            
  685.           }         
  686.      }
  687.    
  688.    return dd->stop;
  689. }
  690.  
  691. BOOL HandleNotify( DOE_Data *dd )
  692. {
  693.      while( !dd->stop && (dd->messages = GetMsg(dd->notify_port)) )
  694.      {
  695.         switch( ((DOpusNotify *) dd->messages)->dn_Type )
  696.           {
  697.              case DN_OPUS_QUIT :
  698.                                  dd->stop = TRUE;
  699.                                  break;
  700.                                  
  701.                                  
  702.              case DN_CLOSE_WORKBENCH:                    
  703.              case DN_OPUS_HIDE : // storing our current window state
  704.                                  dd->flags = dd->win ? TRUE : FALSE;
  705.                                                                   
  706.                                  SendCxMsg( (CX_OBJ *) dd->our_cxobj,
  707.                                             CXCMD_DISAPPEAR,
  708.                                             dd->sender ); 
  709.                                  break;
  710.                                  
  711.              case DN_OPEN_WORKBENCH:
  712.              case DN_RESET_WORKBENCH:
  713.              case DN_OPUS_SHOW :
  714.                                  if( dd->flags )
  715.                                       SendCxMsg( (CX_OBJ *) dd->our_cxobj,
  716.                                                  CXCMD_APPEAR,
  717.                                                  dd->sender ); 
  718.                                  break;             
  719.           } 
  720.         
  721.         ReplyFreeMsg( dd->messages );
  722.      }
  723.      
  724.    return dd->stop;
  725. }
  726.  
  727. BOOL HandleIPC( DOE_Data *dd )
  728. {
  729.    while( !dd->stop && (dd->messages = GetMsg(dd->ipc->command_port)) )
  730.      {
  731.         if( ((IPCMessage *) dd->messages)->command & IPCCMD_QUIT )
  732.           {
  733.              dd->stop = TRUE;
  734.           }
  735.         else        
  736.           {
  737.              if( ((IPCMessage *) dd->messages)->command & IPCCMD_SHOW )
  738.                {
  739.                   SendCxMsg((CX_OBJ *) dd->our_cxobj, CXCMD_APPEAR, dd->sender );                  
  740.                }
  741.                
  742.              if( ((IPCMessage *) dd->messages)->command & IPCCMD_NAME )
  743.                {
  744.                   // make a copy...
  745.                   strncpy( dd->name, ((PassData *) ((IPCMessage *) dd->messages)->data_free)->name, 11 )[11] = 0;
  746.                   
  747.                   // if the supplied name is empty, it does fallback to the buildin name
  748.                   dd->itext.IText = strlen(dd->name) ? dd->name : DOpusGetString( locale, MSG_TEXT );
  749.                }
  750.                     
  751.              if( ((IPCMessage *) dd->messages)->command & IPCCMD_BGC )
  752.                {
  753.                   dd->itext.BackPen = ((PassData *) ((IPCMessage *) dd->messages)->data_free)->BackPen;
  754.                }
  755.                
  756.              if( ((IPCMessage *) dd->messages)->command & IPCCMD_TC )
  757.                {
  758.                   dd->itext.FrontPen = ((PassData *) ((IPCMessage *) dd->messages)->data_free)->FrontPen;
  759.                }
  760.                                               
  761.              if( dd->win )
  762.                {
  763.                   // save our current position temporally
  764.                   dd->ibox.Left = dd->win->LeftEdge;
  765.                   dd->ibox.Top  = dd->win->TopEdge;
  766.                        
  767.                   if( ((IPCMessage *) dd->messages)->command & IPCCMD_NAME )
  768.                     {
  769.                        // changing the name does require closing and reopening
  770.                        // of the window since the window size depends from the
  771.                        // name... (and font)
  772.                        
  773.                        CloseWindow( dd->win );
  774.                        OpenWin( dd );
  775.                     }
  776.                   
  777.                   if( ((IPCMessage *) dd->messages)->command & (IPCCMD_BGC | IPCCMD_TC) )
  778.                     {
  779.                        BorderDraw( dd, FALSE );
  780.                     }
  781.                     
  782.                   if( ((IPCMessage *) dd->messages)->command & IPCCMD_HIDE )
  783.                     {                                     
  784.                        SendCxMsg((CX_OBJ *) dd->our_cxobj, CXCMD_DISAPPEAR, dd->sender );                                                                 
  785.                     }
  786.                }           
  787.           }
  788.           
  789.         IPC_Reply( dd->messages );       
  790.      }
  791.    
  792.    return dd->stop;
  793. }
  794.  
  795. /********************************************************************/
  796.  
  797. BOOL SendCxMsg( CX_OBJ *cxobj, ULONG type, struct MsgPort *reply_to )
  798. {
  799.    FakeMsg *fmsg;
  800.    
  801.    // create a fake CxMsg (not documented..., size is 232 bytes)
  802.    // and send it to the choosed CxObj
  803.    
  804.    if( (fmsg = AllocMemH(mempool, 232)) )
  805.      {
  806.         fmsg->msg.mn_Node.ln_Type = NT_MESSAGE;
  807.         fmsg->msg.mn_Length       = 232;
  808.         fmsg->Code                = CXM_COMMAND;                                                   
  809.         fmsg->msg.mn_ReplyPort    = reply_to;
  810.         fmsg->ID                  = type;    
  811.         
  812.         PutMsg( cxobj->cx_port, (struct Message *) fmsg );
  813.         
  814.         return TRUE;
  815.       }
  816.       
  817.    return FALSE;
  818. }
  819.  
  820. /********************************************************************/
  821. // saving/reading the config
  822. // normally I use for this an own file, but since here is only to
  823. // write some small values... :)
  824.  
  825. // the following include is only needed to use some defines of it
  826. #include <libraries/iffparse.h>
  827.  
  828. // now we are doing some ID's 
  829. // each data block, which should be recognizeable must have an ID
  830. // (=header)
  831.  
  832. #define  DOE_ID           MAKE_ID('D','O','E','X')
  833. #define  LEFT_TOP         MAKE_ID('L','E','T','E')
  834. #define  COLOURS          MAKE_ID('C','O','L','R')
  835. #define  NEW_NAME         MAKE_ID('N','A','M','E')
  836.  
  837.  
  838. BOOL WriteConfig( DOE_Data *dd )
  839. {
  840.      APTR iffhandle;
  841.      ULONG size;
  842.      
  843.      // open our config file for writing     
  844.      if( (iffhandle = IFFOpen(CONFIG_FILE, IFF_WRITE, DOE_ID)) )
  845.        {  
  846.           // here you can see it is possible to write more than one value
  847.           // with one step, they must only follow each other...          
  848.           IFFWriteChunk( iffhandle, &dd->win->LeftEdge, LEFT_TOP, sizeof(WORD) * 2 );
  849.           IFFWriteChunk( iffhandle, &dd->itext.FrontPen, COLOURS, sizeof(UBYTE) * 2 );
  850.           
  851.           if( (size = strlen(dd->name)) )
  852.             {
  853.                // it's a nice idea to write the \0 of the string too,
  854.                // it does save us work on reading the data
  855.                IFFWriteChunk( iffhandle, dd->name, NEW_NAME, size + 1 );
  856.             }
  857.             
  858.           IFFClose( iffhandle );
  859.           return 0;
  860.         };
  861.                  
  862.      return 1;
  863. }
  864.  
  865. // also simple to understand...
  866.  
  867. BOOL ReadConfig( DOE_Data *dd )
  868. {
  869.      APTR iffhandle;
  870.      ULONG nextchunk;
  871.      
  872.      // open the config file for reading     
  873.      if( (iffhandle = IFFOpen(CONFIG_FILE, IFF_READ, DOE_ID)) )
  874.        {
  875.           // IFFNextChunk() does return the next ID (or NULL if there is none)
  876.           // and so we can switch here
  877.           while( (nextchunk = IFFNextChunk(iffhandle, 0)) )
  878.             {
  879.                 switch( nextchunk )
  880.                   {                                                                                                                                
  881.                        case LEFT_TOP: IFFReadChunkBytes(iffhandle, &dd->ibox, sizeof(WORD) * 2 );
  882.                                       break;
  883.                                       
  884.                        case COLOURS : IFFReadChunkBytes(iffhandle, &dd->itext.FrontPen, sizeof(UBYTE) * 2 );
  885.                                       break;
  886.                                       
  887.                        case NEW_NAME: // if a string should be readed, it is needed to use the
  888.                                       // string alone in a chunk or at least to have it at the
  889.                                       // end of a structure - or -
  890.                                       // if you do this not, you must always write the whole
  891.                                       // structure
  892.                                       // if you try to read an alone written string, you
  893.                                       // must always set the size to read to the lenght of
  894.                                       // you string buffer
  895.                                       
  896.                                       IFFReadChunkBytes(iffhandle, dd->name, 16 );
  897.                                       break;  
  898.                   };
  899.             };
  900.           IFFClose( iffhandle );
  901.                
  902.           return 0;
  903.          
  904.        };
  905.      return 1;
  906. }
  907.